package com.ssy.lingxi.product.serviceImpl.customer;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.product.api.model.request.CustomerCategoryAttributeRequest;
import com.ssy.lingxi.product.api.model.request.CustomerCategoryAttributeSortRequest;
import com.ssy.lingxi.product.common.enums.CommodityAttributeTypeEnum;
import com.ssy.lingxi.product.entity.commodity.Commodity;
import com.ssy.lingxi.product.entity.customer.CustomerAttribute;
import com.ssy.lingxi.product.entity.customer.CustomerAttributeValue;
import com.ssy.lingxi.product.entity.customer.CustomerCategory;
import com.ssy.lingxi.product.entity.customer.ProductCustomerCategoryAttribute;
import com.ssy.lingxi.product.repository.commodity.CommodityRepository;
import com.ssy.lingxi.product.repository.customer.CustomerAttributeRepository;
import com.ssy.lingxi.product.repository.customer.CustomerCategoryRepository;
import com.ssy.lingxi.product.repository.customer.ProductCustomerCategoryAttributeRepository;
import com.ssy.lingxi.product.service.customer.ICustomerCategoryAttributeService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.text.Collator;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 品类属性实现类
 * @author jw.chen
 * @version 2.0.0
 * @date 2020/6/22
 */
@Service
public class CustomerCategoryAttributeServiceImpl implements ICustomerCategoryAttributeService {

    @Autowired
    private CustomerCategoryRepository customerCategoryRepository;

    @Autowired
    private CustomerAttributeRepository customerAttributeRepository;

    @Autowired
    private CommodityRepository commodityRepository;

    @Resource
    private ProductCustomerCategoryAttributeRepository productCustomerCategoryAttributeRepository;

    @Resource
    private IRedisStringUtils redisStringUtils;


    /**
     * 查询品类属性
     * @param pageVO
     * @param name
     * @param categoryId
     * @param isByCategory
     * @return Page<CustomerCategoryAttribute>
     */
    @Override
    public Page<CustomerAttribute> getCustomerCategoryAttributeList(UserLoginCacheDTO sysUser, PageVO pageVO, String name, String groupName, Long categoryId, Boolean isByCategory) {
        //查询是否存在该品类
        CustomerCategory customerCategory = customerCategoryRepository.findById(categoryId).orElse(null);
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize());
        Page<CustomerAttribute> result;
        if (customerCategory != null) {
            if (isByCategory) {
                result = customerAttributeRepository.findByMemberIdAndMemberRoleIdAndNameContainingAndCustomerCategoryListId(sysUser.getMemberId(), sysUser.getMemberRoleId(), name, categoryId, page);
                supplementSort(result, categoryId);
            } else {
                List<CustomerAttribute> customerAttributeList = customerCategory.getCustomerAttributeList();
                List<Long> idNotList = customerAttributeList.stream().map(CustomerAttribute::getId).collect(Collectors.toList());
                result = customerAttributeRepository.findAll(getSpecification(sysUser, name, groupName, idNotList), page);
                supplementSort(result, categoryId);
            }
            return result;
        } else {
            throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
        }
    }

    private void supplementSort(Page<CustomerAttribute> result, Long categoryId) {
        Map<Integer, Integer> productCustomerCategoryAttributeMap = productCustomerCategoryAttributeRepository.findAllByCategoryId(categoryId.intValue())
                .stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(ProductCustomerCategoryAttribute::getAttributeId, ProductCustomerCategoryAttribute::getSort));
        result.getContent().forEach(customerAttribute -> {
            Integer sort = productCustomerCategoryAttributeMap.get(customerAttribute.getId().intValue());
            customerAttribute.setSort(Objects.nonNull(sort) ? sort : 0);
        });
    }


    /**
     * 查询品类属性
     * @param name
     * @param categoryId
     * @param isByCategory
     * @return List<CustomerCategoryAttribute>
     */
    @Override
    public List<CustomerAttribute> getMroCustomerCategoryAttributeList(UserLoginCacheDTO sysUser, String name, String groupName, Long categoryId, Boolean isByCategory) {
        //查询是否存在该品类
        CustomerCategory customerCategory = customerCategoryRepository.findById(categoryId).orElse(null);
        if (customerCategory != null) {
//            List<Long> subCategoryIdList = getSubCategoryIdList(customerCategory.getId());
            List<CustomerAttribute> sortedCustomerAttributeList;
            if (isByCategory) {
                sortedCustomerAttributeList = sortResult(customerAttributeRepository.findByNameContainingAndCustomerCategoryListIdIn(name, new ArrayList<Long>(){{add(categoryId);}}), categoryId,Boolean.TRUE);
            } else {
                List<CustomerAttribute> customerAttributeList = customerCategory.getCustomerAttributeList();
                List<Long> idNotList = customerAttributeList.stream().map(CustomerAttribute::getId).collect(Collectors.toList());
                sortedCustomerAttributeList = sortResult(customerAttributeRepository.findAll(getSpecification(sysUser, name, groupName, idNotList)), categoryId,Boolean.TRUE);
            }
            return sortedCustomerAttributeList;
        } else {
            throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
        }
    }

    /**
     * 获取当前品类的子品类id 包含本品类id
     * @param categoryId
     * @return
     */
    @Override
    public List<Long> getSubCategoryIdList(Long categoryId) {
        String newCategoryId = String.format(Constants.CATEGORY_FULL_ID_NUM, categoryId);
        List<CustomerCategory> list = customerCategoryRepository.findByFullIdLike("%"+newCategoryId+"%");
        List<String> fullIdList = new ArrayList<>();
        for (CustomerCategory item : list) {
            List<String> tempList = Arrays.asList(item.getFullId().split("\\."));
            fullIdList = tempList.size() > fullIdList.size() ? tempList : fullIdList;
        }
        Integer index = null;
        List<Long> subCategoryIdList = new ArrayList<>();
        for (int i = 0; i < fullIdList.size(); i++) {
            if (newCategoryId.equals(fullIdList.get(i))) {
                index = i;
            }
            if (Objects.nonNull(index)) {
                subCategoryIdList.add(Long.valueOf(fullIdList.get(i)));
            }
        }
        return subCategoryIdList;
    }

    /**
     * 给结果排序 MRO模式
     *
     * @param customerAttributeList
     * @return
     */
    private List<CustomerAttribute> sortResult(List<CustomerAttribute> customerAttributeList, Long categoryId,Boolean openMro) {
        //查询会员品类属性中间表
        List<ProductCustomerCategoryAttribute> productCustomerCategoryAttributeList = productCustomerCategoryAttributeRepository.findAllByCategoryId(categoryId.intValue());

        //过滤无效的属性
        customerAttributeList = filterInvalidAttribute(customerAttributeList);

        //过滤无效的属性值
        filterInvalidAttributeValue(customerAttributeList);

        //将中间表数据转成map
        Map<Integer, Integer> map = turnListToMap(productCustomerCategoryAttributeList);

        //开启MRO之后，属性按照sort排序，然后按照id倒叙排序，属性值按照自定义的比较器排序
        return customerAttributeList
                .stream()
                .filter(this::distinctCustomerAttribute)
                .peek(customerAttribute -> setCustomerAttributeSort(map, customerAttribute))
                .sorted(Comparator.comparing(CustomerAttribute::getSort)
                        .thenComparing(CustomerAttribute::getId, Comparator.reverseOrder()))
                .peek(customerAttribute -> {
                    if (openMro) {
                        sortCustomerAttribute(customerAttribute);
                    }
                })
                .collect(Collectors.toList());
    }


    /**
     * 给会员属性值排序
     *
     * @param customerAttribute
     */
    private void sortCustomerAttribute(CustomerAttribute customerAttribute) {
        Comparator<Object> comparator = Collator.getInstance(Locale.CHINESE);
        customerAttribute.setCustomerAttributeValueList(customerAttribute.getCustomerAttributeValueList()
                .stream()
                .sorted((p1, p2) -> comparator.compare(p1.getValue(), p2.getValue()))
                .collect(Collectors.toList()));
    }

    /**
     * 将中间表数据转成map
     *
     * @param productCustomerCategoryAttributeList
     */
    private Map<Integer, Integer> turnListToMap(List<ProductCustomerCategoryAttribute> productCustomerCategoryAttributeList) {
        return productCustomerCategoryAttributeList.stream().collect(Collectors.toMap(ProductCustomerCategoryAttribute::getAttributeId, ProductCustomerCategoryAttribute::getSort));
    }

    /**
     * 设置会员属性排序
     *
     * @param map
     * @param customerAttribute
     */
    private void setCustomerAttributeSort(Map<Integer, Integer> map, CustomerAttribute customerAttribute) {
        customerAttribute.setSort(Objects.nonNull(map.get(customerAttribute.getId().intValue())) ? map.get(customerAttribute.getId().intValue()) : 0);
    }

    /**
     * 去重会员属性
     *
     * @param customerAttribute
     * @return
     */
    private boolean distinctCustomerAttribute(CustomerAttribute customerAttribute) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return seen.putIfAbsent(customerAttribute.getId(), Boolean.TRUE) == null;
    }

    /**
     * 过滤无效的属性值
     * @param customerAttributeList
     */
    private void filterInvalidAttributeValue(List<CustomerAttribute> customerAttributeList) {
        customerAttributeList.forEach(customerAttribute -> {
            if (CollectionUtil.isNotEmpty(customerAttribute.getCustomerAttributeValueList())) {
                List<CustomerAttributeValue> customerAttributeValueList = customerAttribute.getCustomerAttributeValueList()
                        .stream()
                        .filter(CustomerAttributeValue::getIsEnable)
                        .collect(Collectors.toList());
                customerAttribute.setCustomerAttributeValueList(customerAttributeValueList);
            }
        });
    }

    /**
     * 过滤无效的属性
     * @param customerAttributeList
     * @return
     */
    private List<CustomerAttribute> filterInvalidAttribute(List<CustomerAttribute> customerAttributeList) {
        customerAttributeList = customerAttributeList
                .stream()
                .filter(CustomerAttribute::getIsEnable)
                .filter(item-> !CommodityAttributeTypeEnum.Input.getCode().equals(item.getType()))
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(()->
                                new TreeSet<>(Comparator.comparing(CustomerAttribute::getId))),ArrayList::new)
                );
        return customerAttributeList;
    }

    /**
     * 给结果排序
     *
     * @param customerAttributeList
     * @return
     */
    private List<CustomerAttribute> sortResult(List<CustomerAttribute> customerAttributeList, Long categoryId) {
        List<ProductCustomerCategoryAttribute> productCustomerCategoryAttributeList = productCustomerCategoryAttributeRepository.findAllByCategoryId(categoryId.intValue());
        Map<Integer, Integer> map = productCustomerCategoryAttributeList
                .stream()
                .collect(Collectors.toMap(ProductCustomerCategoryAttribute::getAttributeId, ProductCustomerCategoryAttribute::getSort));
        return customerAttributeList
                .stream()
                .peek(customerAttribute -> customerAttribute.setSort(Objects.nonNull(map.get(customerAttribute.getId().intValue())) ? map.get(customerAttribute.getId().intValue()) : 0))
                .sorted(Comparator.comparing(CustomerAttribute::getSort)
                        .thenComparing(CustomerAttribute::getId, Comparator.reverseOrder()))
                .collect(Collectors.toList());
    }


    /**
     * 添加/修改品类属性
     * @param customerCategoryAttributeVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveCustomerCategoryAttribute(UserLoginCacheDTO sysUser, CustomerCategoryAttributeRequest customerCategoryAttributeVO){
        Long memberId = sysUser.getMemberId();
        Long memberRoleId = sysUser.getMemberRoleId();
        //获取参数值
        Long customerCategoryId = customerCategoryAttributeVO.getCustomerCategoryId();
        //查询是否存在该品类
        CustomerCategory customerCategory = customerCategoryRepository.findById(customerCategoryId).orElse(null);
        if(customerCategory == null){
            throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
        }
        //查询是否存在该属性列表
        List<Long> attributeIdList = customerCategoryAttributeVO.getCustomerAttributeIds();
        List<CustomerAttribute> customerAttributeList = customerAttributeRepository.findByMemberIdAndMemberRoleIdAndIdIn(memberId, memberRoleId, attributeIdList);
        if(customerAttributeList.isEmpty() || customerAttributeList.size() != attributeIdList.size()){
            throw new BusinessException(ResponseCode.PRODUCT_ATTRIBUTE_NOT_EXIST);
        }

        List<ProductCustomerCategoryAttribute> oldCustomerAttributeSort = findProductCustomerCategoryAttributeData(customerCategoryId);

        //合并之前的属性
        List<CustomerAttribute> oldCustomerAttributeList = customerCategory.getCustomerAttributeList();
        if(oldCustomerAttributeList != null && !oldCustomerAttributeList.isEmpty()){
            customerAttributeList.addAll(oldCustomerAttributeList);
        }
        //设置对应关系
        customerCategory.setCustomerAttributeList(customerAttributeList);


        //数据库持久化对象
        customerCategoryRepository.saveAndFlush(customerCategory);

        List<ProductCustomerCategoryAttribute> newCustomerAttributeSort = findProductCustomerCategoryAttributeData(customerCategoryId);

        resetSort(oldCustomerAttributeSort, newCustomerAttributeSort);

        return ResponseCode.SUCCESS.getMessage();
    }

    /**
     * 重新设置sort
     * 方法主要做的事情是匹配两个List中categoryId和attributeId相等的对象
     * 如果存在，则用旧的对象sort给新的对象赋值
     * 如果不存在，则不做处理
     * 可适用于新增，修改，删除品类属性后reset中间表的sort字段
     *
     * @param oldCustomerAttributeSort
     * @param newCustomerAttributeSort
     */
    public void resetSort(List<ProductCustomerCategoryAttribute> oldCustomerAttributeSort, List<ProductCustomerCategoryAttribute> newCustomerAttributeSort) {
        List<ProductCustomerCategoryAttribute> productCustomerCategoryAttributeList = newCustomerAttributeSort
                .stream()
                .map(newData -> oldCustomerAttributeSort
                        .stream()
                        .map(oldData -> {
                            if (attributeEquals(oldData, newData)) {
                                newData.setSort(oldData.getSort());
                            }
                            return newData;
                        })
                        .collect(Collectors.toList())
                )
                .flatMap(List::stream)
                .collect(Collectors
                        .collectingAndThen(
                                Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getCategoryId() + ";" + o.getAttributeId()))), ArrayList::new));
        productCustomerCategoryAttributeList.forEach(item ->
                productCustomerCategoryAttributeRepository.updateData(item.getCategoryId(), item.getAttributeId(), item.getSort())
        );
    }

    /**
     * 比较两份数据的attributeId是否相等
     *
     * @param newData
     * @param oldData
     * @return
     */
    private boolean attributeEquals(ProductCustomerCategoryAttribute newData, ProductCustomerCategoryAttribute oldData) {
        return oldData.getAttributeId().equals(newData.getAttributeId());
    }

    /**
     * 根据categoryId查询中间表数据
     * @param customerCategoryId
     * @return
     */
    private List<ProductCustomerCategoryAttribute> findProductCustomerCategoryAttributeData(Long customerCategoryId) {
        return productCustomerCategoryAttributeRepository.findAllByCategoryId(customerCategoryId.intValue());
    }

    /**
     * 删除品类属性
     * @param customerCategoryAttributeVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteCustomerCategoryAttribute(UserLoginCacheDTO sysUser, CustomerCategoryAttributeRequest customerCategoryAttributeVO) {
        Long memberId = sysUser.getMemberId();
        Long memberRoleId = sysUser.getMemberRoleId();
        //获取参数值
        List<Long> attributeIdList = customerCategoryAttributeVO.getCustomerAttributeIds();
        Long customerCategoryId = customerCategoryAttributeVO.getCustomerCategoryId();
        //查询是否存在该属性列表
        List<CustomerAttribute> customerAttributeList = customerAttributeRepository.findByMemberIdAndMemberRoleIdAndIdIn(memberId, memberRoleId, attributeIdList);
        if(customerAttributeList.isEmpty() || customerAttributeList.size() != attributeIdList.size()){
            throw new BusinessException(ResponseCode.PRODUCT_ATTRIBUTE_NOT_EXIST);
        }
        //查询是否存在该品类
        CustomerCategory customerCategory = customerCategoryRepository.findById(customerCategoryId).orElse(null);
        if(customerCategory == null){
            throw new BusinessException(ResponseCode.PRODUCT_CATEGORY_NOT_EXIST);
        }
        //判断是否存在关联关系
        List<CustomerAttribute> currentList = customerCategory.getCustomerAttributeList();
        if(currentList != null && !currentList.isEmpty() && currentList.containsAll(customerAttributeList)){
            //判断是否有商品还在使用
            List<Commodity> commodityList = commodityRepository.findByMemberIdAndMemberRoleIdAndCustomerCategoryIdAndCommodityAttributeListCustomerAttributeIdIn(memberId, memberRoleId, customerCategoryId, attributeIdList);
            if(!commodityList.isEmpty()){
                throw new BusinessException(ResponseCode.PRODUCT_COMMODITY_RELATION_NOT_DELETE);
            }
        }else{
            throw new BusinessException(ResponseCode.PRODUCT_ATTRIBUTE_NOT_EXIST);
        }
        //删除绑定关系
        customerCategory.getCustomerAttributeList().removeAll(customerAttributeList);

        List<ProductCustomerCategoryAttribute> oldCustomerCategoryAttributeList = findProductCustomerCategoryAttributeData(customerCategoryId);

        customerCategoryRepository.saveAndFlush(customerCategory);

        List<ProductCustomerCategoryAttribute> newCustomerCategoryAttributeList = findProductCustomerCategoryAttributeData(customerCategoryId);

        resetSort(oldCustomerCategoryAttributeList,newCustomerCategoryAttributeList);

        List<String> fieldList = attributeIdList.stream().map(String::valueOf).collect(Collectors.toList());

        //删除缓存中对应的品类属性排序
        redisStringUtils.hDel(Constants.REDIS_KEY_CUSTOMER_CATEGORY_ATTRIBUTE_SORT + customerCategoryId,fieldList,Constants.REDIS_PRODUCT_INDEX);

        return "解绑成功";
    }

    /**
     * 构建查询条件
     */
    private Specification<CustomerAttribute> getSpecification(UserLoginCacheDTO sysUser, String name, String groupName, List<Long> idNotInList){
        return (Specification<CustomerAttribute>) (root, query, criteriaBuilder) -> {
            Long memberId = sysUser.getMemberId();
            Long memberRoleId = sysUser.getMemberRoleId();

            Predicate finalConditions = criteriaBuilder.conjunction();

            //id筛选
            if(idNotInList != null && !idNotInList.isEmpty()){
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.not(criteriaBuilder.in(root.get("id")).value(idNotInList)));
            }

            //属性名称
            if(!StringUtils.isEmpty(name)){
                Predicate predicate = criteriaBuilder.like(root.get("name").as(String.class), "%" + name + "%");
                finalConditions = criteriaBuilder.and(finalConditions, predicate);
            }

            //属性组名称
            if(!StringUtils.isEmpty(groupName)){
                Predicate predicate = criteriaBuilder.like(root.get("groupName").as(String.class), "%" + groupName + "%");
                finalConditions = criteriaBuilder.and(finalConditions, predicate);
            }

            //会员id
            if(memberId != null && memberId > 0){
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.equal(root.get("memberId").as(Long.class), memberId));
            }

            //会员角色id
            if(memberRoleId != null && memberRoleId > 0){
                finalConditions = criteriaBuilder.and(finalConditions, criteriaBuilder.equal(root.get("memberRoleId").as(Long.class), memberRoleId));
            }

            return  query.where(finalConditions).getRestriction();
        };
    }

    /**
     * 新增/修改品类下的属性排序
     *
     * @param sysUser
     * @param customerCategoryAttributeSortRequestList
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveCustomerCategoryAttributeSort(UserLoginCacheDTO sysUser, List<CustomerCategoryAttributeSortRequest> customerCategoryAttributeSortRequestList) {
        List<ProductCustomerCategoryAttribute> productCustomerCategoryAttributeList = customerCategoryAttributeSortRequestList
                .stream()
                .map(item -> {
                    ProductCustomerCategoryAttribute productCustomerCategoryAttribute = new ProductCustomerCategoryAttribute();
                    BeanUtil.copyProperties(item, productCustomerCategoryAttribute);
                    redisStringUtils.hSet(Constants.REDIS_KEY_CUSTOMER_CATEGORY_ATTRIBUTE_SORT + productCustomerCategoryAttribute.getCategoryId(), String.valueOf(productCustomerCategoryAttribute.getAttributeId()), String.valueOf( productCustomerCategoryAttribute.getSort()), Constants.REDIS_PRODUCT_INDEX);
                    return productCustomerCategoryAttribute;
                }).collect(Collectors.toList());
        productCustomerCategoryAttributeList.forEach(productCustomerCategoryAttribute -> {
            productCustomerCategoryAttributeRepository.updateData(productCustomerCategoryAttribute.getCategoryId(),productCustomerCategoryAttribute.getAttributeId(),productCustomerCategoryAttribute.getSort());
        });
        return true;
    }

//    @Override
//    public Boolean initSortCache() {
//        List<ProductCustomerCategoryAttribute> list = productCustomerCategoryAttributeRepository.findAll();
//
//        list.forEach(productCustomerCategoryAttribute -> {
//            redisStringUtils.hSet(Constants.REDIS_KEY_CUSTOMER_CATEGORY_ATTRIBUTE_SORT + productCustomerCategoryAttribute.getCategoryId(), String.valueOf(productCustomerCategoryAttribute.getAttributeId()), String.valueOf( productCustomerCategoryAttribute.getSort()), Constants.REDIS_PRODUCT_INDEX);
//        });
//
//        return true;    }
}

